1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.hiprenderer.backend.d3d.d3dshader; 12 13 version(Windows): 14 version(DirectX): 15 import hip.config.opts; 16 import hip.hiprenderer.renderer; 17 import hip.api.renderer.texture; 18 import hip.hiprenderer.shader; 19 import hip.hiprenderer.backend.d3d.d3drenderer; 20 import hip.util.system:getWindowsErrorMessage; 21 import directx.d3d11; 22 import directx.d3dcompiler; 23 import directx.d3d11shader; 24 import hip.util.conv:to; 25 import hip.error.handler; 26 27 28 class Hip_D3D11_FragmentShader : FragmentShader 29 { 30 ID3DBlob shader; 31 ID3D11PixelShader fs; 32 override final string getDefaultFragment() 33 { 34 return q{ 35 float4 main() : SV_TARGET 36 { 37 return float4(1.0f, 1.0f, 1.0f, 1.0f); 38 }}; 39 } 40 override final string getFrameBufferFragment() 41 { 42 return q{ 43 Texture2D uTex1; 44 SamplerState state; 45 46 float4 main(float2 inTexST : inTexST) : SV_TARGET 47 { 48 return uTex1.Sample(state, inTexST); 49 } 50 }; 51 } 52 override final string getGeometryBatchFragment() 53 { 54 return q{ 55 56 cbuffer FragVars 57 { 58 float4 uGlobalColor : uGlobalColor; 59 }; 60 61 float4 main(float4 inVertexColor : inVertexColor) : SV_TARGET 62 { 63 return inVertexColor * uGlobalColor; 64 } 65 }; 66 } 67 /** 68 * Creates a massive switch case for supporting array of textures. 69 * D3D11 causes an error if trying to access texture with a variable 70 * instead of a literal. 71 */ 72 override final string getSpriteBatchFragment() 73 { 74 int sup = HipRenderer.getMaxSupportedShaderTextures(); 75 string textureSlotSwitchCase = "\tswitch(tid)\n\t{\n"; //Switch textureID 76 for(int i = 1; i < sup; i++) 77 { 78 textureSlotSwitchCase~= "\t\tcase "~ to!string(i)~": "~ 79 "return uTex["~to!string(i)~"].Sample(state["~to!string(i)~"], texST) * inVertexColor * uBatchColor;\n"; 80 } 81 textureSlotSwitchCase~= "\t\tdefault: return uTex[0].Sample(state[0], texST) * inVertexColor * uBatchColor;"; 82 textureSlotSwitchCase~= "\n\t}"; 83 84 return "Texture2D uTex["~to!string(sup)~"]; 85 SamplerState state["~to!string(sup)~"];"~q{ 86 cbuffer input 87 { 88 float4 uBatchColor: uBatchColor; 89 }; 90 91 float4 main(float4 inVertexColor : inColor, float2 texST : inTexST, float inTexID : inTexID) : SV_TARGET 92 }~"{"~ 93 q{ 94 // return uBatchColor * uTex.Sample(state, inTexST); 95 int tid = int(inTexID); 96 97 //switch(tid)... 98 //case 1: 99 //return uTex[1].Sample(state[1], texST) * inVertexColor * uBatchColor; 100 } ~ textureSlotSwitchCase ~ "\n}"; 101 } 102 override final string getBitmapTextFragment() 103 { 104 return q{ 105 106 cbuffer FragVars 107 { 108 float4 uColor : uColor; 109 }; 110 111 Texture2D uSampler1; 112 SamplerState state; 113 114 float4 main(float2 inTexST : inTexST) : SV_TARGET 115 { 116 //The texture is read as monochromatic 117 float r = uSampler1.Sample(state, inTexST)[0]; 118 119 return float4(r,r,r,r) * uColor; 120 } 121 }; 122 } 123 } 124 class Hip_D3D11_VertexShader : VertexShader 125 { 126 ID3DBlob shader; 127 ID3D11VertexShader vs; 128 129 override final string getDefaultVertex() 130 { 131 return q{ 132 float4 main(float2 pos : Position) : SV_POSITION 133 { 134 return float4(pos.x, pos.y, 0.0f, 1.0f); 135 }}; 136 } 137 override final string getFrameBufferVertex() 138 { 139 return q{ 140 struct VSOut 141 { 142 float2 inTexST : inTexST; 143 float4 outPosition : SV_POSITION; 144 }; 145 146 VSOut main(float2 pos : vPosition, float2 vTexST : vTexST) 147 { 148 VSOut ret; 149 ret.outPosition = float4(pos.x, pos.y, 0.0, 1.0); 150 ret.inTexST = vTexST; 151 return ret; 152 } 153 }; 154 } 155 override final string getGeometryBatchVertex() 156 { 157 return q{ 158 159 cbuffer Geom 160 { 161 float4x4 uModel: uModel; 162 float4x4 uView : uView; 163 float4x4 uProj : uProj; 164 }; 165 struct VSOut 166 { 167 float4 inVertexColor : inVertexColor; 168 float4 outPosition : SV_POSITION; 169 }; 170 171 VSOut main(float3 vPosition: vPosition, float4 vColor: vColor) 172 { 173 VSOut ret; 174 ret.outPosition = mul(float4(vPosition, 1.0), mul(mul(uModel, uView), uProj)); 175 ret.inVertexColor = vColor; 176 return ret; 177 } 178 }; 179 } 180 override final string getSpriteBatchVertex() 181 { 182 return q{ 183 struct VSOut 184 { 185 float4 inColor : inColor; 186 float2 inTexST : inTexST; 187 float inTexID : inTexID; 188 float4 vPosition: SV_POSITION; 189 }; 190 191 cbuffer Cbuf 192 { 193 float4x4 uProj; 194 float4x4 uModel; 195 float4x4 uView; 196 }; 197 198 VSOut main( 199 float3 pos : vPosition, 200 float4 col : vColor, 201 float2 texST : vTexST, 202 float texID : vTexID 203 ) 204 { 205 VSOut output; 206 float4 position = float4(pos.x, pos.y, pos.z, 1.0f); 207 output.vPosition = mul(position, mul(mul(uModel, uView), uProj)); 208 209 output.inTexST = texST; 210 output.inColor = col; 211 output.inTexID = texID; 212 return output; 213 } 214 }; 215 } 216 override final string getBitmapTextVertex() 217 { 218 return q{ 219 220 cbuffer Cbuf 221 { 222 float4x4 uModel; 223 float4x4 uView; 224 float4x4 uProj; 225 }; 226 227 struct VSOut 228 { 229 float2 inTexST : inTexST; 230 float4 outPosition : SV_POSITION; 231 }; 232 233 VSOut main(float2 vPosition : vPosition, float2 vTexST : vTexST) 234 { 235 VSOut ret; 236 ret.outPosition = mul(float4(vPosition, 1.0, 1.0), mul(mul(uModel, uView), uProj)); 237 ret.inTexST = vTexST; 238 return ret; 239 } 240 }; 241 } 242 } 243 class Hip_D3D11_ShaderProgram : ShaderProgram 244 { 245 Hip_D3D11_VertexShader vs; 246 Hip_D3D11_FragmentShader fs; 247 248 protected HipBlendFunction blendSrc, blendDst; 249 protected HipBlendEquation blendEq; 250 protected ID3D11BlendState blendState; 251 252 ID3D11ShaderReflection vReflector; 253 ID3D11ShaderReflection pReflector; 254 255 bool initialize() 256 { 257 import hip.hiprenderer; 258 auto hres = D3DReflect(vs.shader.GetBufferPointer(), 259 vs.shader.GetBufferSize(), &IID_ID3D11ShaderReflection, cast(void**)&vReflector); 260 if(FAILED(hres)) 261 { 262 ErrorHandler.showErrorMessage("D3D11 ShaderProgram initialization", 263 "Could not get the reflection interface from the vertex shader, error: "~ getWindowsErrorMessage(hres)); 264 return false; 265 } 266 hres = D3DReflect(fs.shader.GetBufferPointer(), 267 fs.shader.GetBufferSize(), &IID_ID3D11ShaderReflection, cast(void**)&pReflector); 268 if(FAILED(hres)) 269 { 270 ErrorHandler.showErrorMessage("D3D11 ShaderProgram initialization", 271 "Could not get the reflection interface from the pixel shader, error: "~ getWindowsErrorMessage(hres)); 272 return false; 273 } 274 return true; 275 } 276 } 277 278 struct Hip_D3D11_ShaderVarAdditionalData 279 { 280 ID3D11Buffer buffer; 281 uint id; 282 } 283 284 package D3D11_BLEND getD3DBlendFunc(HipBlendFunction func) 285 { 286 final switch(func) with(HipBlendFunction) 287 { 288 case ZERO: return D3D11_BLEND_ZERO; 289 case ONE: return D3D11_BLEND_ONE; 290 291 case SRC_COLOR: return D3D11_BLEND_SRC_COLOR; 292 case ONE_MINUS_SRC_COLOR: return D3D11_BLEND_INV_SRC_COLOR; 293 294 case DST_COLOR: return D3D11_BLEND_DEST_COLOR; 295 case ONE_MINUS_DST_COLOR: return D3D11_BLEND_INV_DEST_COLOR; 296 297 case SRC_ALPHA: return D3D11_BLEND_SRC_ALPHA; 298 case ONE_MINUS_SRC_ALPHA: return D3D11_BLEND_INV_SRC_ALPHA; 299 300 case DST_ALPHA: return D3D11_BLEND_DEST_ALPHA; 301 case ONE_MINUS_DST_ALPHA: return D3D11_BLEND_INV_DEST_ALPHA; 302 303 case CONSTANT_COLOR: return D3D11_BLEND_SRC1_COLOR; 304 case ONE_MINUS_CONSTANT_COLOR: return D3D11_BLEND_INV_SRC1_COLOR; 305 306 case CONSTANT_ALPHA: return D3D11_BLEND_SRC1_ALPHA; 307 case ONE_MINUS_CONSTANT_ALPHA: return D3D11_BLEND_INV_SRC1_ALPHA; 308 } 309 } 310 package D3D11_BLEND_OP getD3DBlendEquation(HipBlendEquation eq) 311 { 312 final switch(eq) with (HipBlendEquation) 313 { 314 case DISABLED:return D3D11_BLEND_OP_ADD; 315 case ADD:return D3D11_BLEND_OP_ADD; 316 case SUBTRACT:return D3D11_BLEND_OP_SUBTRACT; 317 case REVERSE_SUBTRACT:return D3D11_BLEND_OP_REV_SUBTRACT; 318 case MIN:return D3D11_BLEND_OP_MIN; 319 case MAX:return D3D11_BLEND_OP_MAX; 320 } 321 } 322 323 class Hip_D3D11_ShaderImpl : IShader 324 { 325 import hip.util.data_structures:Pair; 326 FragmentShader createFragmentShader() 327 { 328 Hip_D3D11_FragmentShader fs = new Hip_D3D11_FragmentShader(); 329 fs.shader = null; 330 fs.fs = null; 331 return cast(FragmentShader)fs; 332 } 333 VertexShader createVertexShader() 334 { 335 Hip_D3D11_VertexShader vs = new Hip_D3D11_VertexShader(); 336 vs.shader = null; 337 vs.vs = null; 338 return cast(VertexShader)vs; 339 } 340 ShaderProgram createShaderProgram() 341 { 342 Hip_D3D11_ShaderProgram prog = new Hip_D3D11_ShaderProgram(); 343 return prog; 344 } 345 346 bool compileShader(ref ID3DBlob shaderPtr, string shaderPrefix, string shaderSource) 347 { 348 shaderSource~="\0"; 349 350 string shaderType = shaderPrefix == "ps" ? "Pixel Shader" : "Vertex Shader"; 351 char* source = cast(char*)shaderSource.ptr; 352 353 //No #includes 354 355 uint compile_flags = D3DCOMPILE_ENABLE_STRICTNESS; 356 uint effects_flags = 0; 357 ID3DBlob shader = null; 358 ID3DBlob error = null; 359 shaderPrefix~= "_5_0\0"; //Append version on shader type 360 361 362 static if(HIP_DEBUG) 363 { 364 compile_flags|= D3DCOMPILE_WARNINGS_ARE_ERRORS; 365 compile_flags|= D3DCOMPILE_DEBUG; 366 compile_flags|= D3DCOMPILE_SKIP_OPTIMIZATION; 367 } 368 else static if(HIP_OPTIMIZE) 369 compile_flags|= D3DCOMPILE_OPTIMIZATION_LEVEL3; 370 371 const D3D_SHADER_MACRO[] defines = 372 [ 373 cast(D3D_SHADER_MACRO)null, cast(D3D_SHADER_MACRO)null 374 ]; 375 376 HRESULT hr = D3DCompile(source, shaderSource.length+1, null, 377 defines.ptr, null, "main", shaderPrefix.ptr, compile_flags, effects_flags, &shader, &error); 378 shaderPtr = shader; 379 380 if(ErrorHandler.assertLazyErrorMessage(SUCCEEDED(hr), shaderType~" compilation error", "Compilation failed")) 381 { 382 if(error !is null) 383 { 384 string errMessage = to!string(cast(char*)error.GetBufferPointer()); 385 ErrorHandler.showErrorMessage("Shader Source Error: ", shaderSource); 386 ErrorHandler.showErrorMessage("Compilation error:", errMessage); 387 error.Release(); 388 } 389 if(shader) 390 shader.Release(); 391 return false; 392 } 393 return true; 394 } 395 bool compileShader(VertexShader _vs, string shaderSource) 396 { 397 Hip_D3D11_VertexShader vs = cast(Hip_D3D11_VertexShader)_vs; 398 bool compiledCorrectly = compileShader(vs.shader, "vs", shaderSource); 399 if(compiledCorrectly) 400 { 401 auto res = _hip_d3d_device.CreateVertexShader(vs.shader.GetBufferPointer(), 402 vs.shader.GetBufferSize(), null, &vs.vs); 403 if(ErrorHandler.assertErrorMessage(SUCCEEDED(res), "Vertex shader creation error", "Creation failed")) 404 { 405 ErrorHandler.showErrorMessage("Vertex Shader Error:", getWindowsErrorMessage(res)); 406 compiledCorrectly = false; 407 } 408 } 409 return compiledCorrectly; 410 } 411 bool compileShader(FragmentShader _fs, string shaderSource) 412 { 413 auto fs = cast(Hip_D3D11_FragmentShader)_fs; 414 bool compiledCorrectly = compileShader(fs.shader, "ps", shaderSource); 415 if(compiledCorrectly) 416 { 417 auto res = _hip_d3d_device.CreatePixelShader(fs.shader.GetBufferPointer(), fs.shader.GetBufferSize(), null, &fs.fs); 418 if(ErrorHandler.assertErrorMessage(SUCCEEDED(res), "Fragment/Pixel shader creation error", "Creation failed")) 419 { 420 ErrorHandler.showErrorMessage("Fragment Shader Error:", getWindowsErrorMessage(res)); 421 compiledCorrectly = false; 422 } 423 } 424 return compiledCorrectly; 425 } 426 427 bool linkProgram(ref ShaderProgram _program, VertexShader vs, FragmentShader fs) 428 { 429 auto program = cast(Hip_D3D11_ShaderProgram)_program; 430 program.vs = cast(Hip_D3D11_VertexShader)vs; 431 program.fs = cast(Hip_D3D11_FragmentShader)fs; 432 return program.initialize(); 433 } 434 435 436 /** 437 * params: 438 * layoutIndex: The layout index defined on shader 439 * valueAmount: How many values using, for 3 vertices, you can use 3 440 * dataType: Which data type to send 441 * normalize: If it will normalize 442 * stride: Target value amount in bytes, for instance, vec3 is float.sizeof*3 443 * offset: It will be calculated for each value index 444 * 445 */ 446 void sendVertexAttribute(uint layoutIndex, int valueAmount, uint dataType, bool normalize, uint stride, int offset) 447 { 448 // glVertexAttribPointer(layoutIndex, valueAmount, dataType, normalize, stride, cast(void*)offset); 449 // glEnableVertexAttribArray(layoutIndex); 450 } 451 452 void bind(ShaderProgram _program) 453 { 454 Hip_D3D11_ShaderProgram p = cast(Hip_D3D11_ShaderProgram)_program; 455 if(p.blendState !is null && 456 (p.blendDst != currDst || 457 p.blendSrc != currSrc || 458 p.blendEq != currEq)) 459 { 460 currEq = p.blendEq; 461 currSrc = p.blendSrc; 462 currDst = p.blendDst; 463 _hip_d3d_context.OMSetBlendState(p.blendState, null, 0xFF_FF_FF_FF); 464 } 465 _hip_d3d_context.VSSetShader(p.vs.vs, cast(ID3D11ClassInstance*)0, 0u); 466 _hip_d3d_context.PSSetShader(p.fs.fs, cast(ID3D11ClassInstance*)0, 0u); 467 } 468 void unbind(ShaderProgram _program) 469 { 470 _hip_d3d_context.VSSetShader(null, cast(ID3D11ClassInstance*)0, 0u); 471 _hip_d3d_context.PSSetShader(null, cast(ID3D11ClassInstance*)0, 0u); 472 } 473 474 int getId(ref ShaderProgram prog, string name) 475 { 476 import hip.error.handler; 477 Hip_D3D11_ShaderProgram p = cast(Hip_D3D11_ShaderProgram)prog; 478 D3D11_SHADER_INPUT_BIND_DESC output; 479 480 481 if(!SUCCEEDED(p.vReflector.GetResourceBindingDescByName(name.ptr, &output))) 482 { 483 ErrorHandler.showErrorMessage("Error finding ID/Uniform for shader ", "For variable named "~name ~ " in shader " ~ prog.name); 484 } 485 486 487 return output.BindPoint; 488 } 489 490 void sendVars(ref ShaderProgram prog, ShaderVariablesLayout[string] layouts) 491 { 492 D3D11_SHADER_INPUT_BIND_DESC desc; 493 Hip_D3D11_ShaderProgram p = cast(Hip_D3D11_ShaderProgram)prog; 494 foreach(k, _; layouts) 495 { 496 import core.stdc.string:memcpy; 497 ShaderVariablesLayout l = cast(ShaderVariablesLayout)layouts[k]; 498 Hip_D3D11_ShaderVarAdditionalData* data = cast(Hip_D3D11_ShaderVarAdditionalData*)l.getAdditionalData(); 499 D3D11_MAPPED_SUBRESOURCE resource; 500 _hip_d3d_context.Map(data.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); 501 memcpy(resource.pData, l.getBlockData(), l.getLayoutSize()); 502 _hip_d3d_context.Unmap(data.buffer, 0); 503 504 ErrorHandler.assertExit(data != null, "D3D11 ShaderVarAdditionalData is null, can't send variables"); 505 506 final switch(l.shaderType) 507 { 508 case ShaderTypes.FRAGMENT: 509 p.pReflector.GetResourceBindingDescByName((l.name~"\0").ptr, &desc); 510 _hip_d3d_context.PSSetConstantBuffers(desc.BindPoint, 1, &data.buffer); 511 break; 512 case ShaderTypes.VERTEX: 513 p.vReflector.GetResourceBindingDescByName((l.name~"\0").ptr, &desc); 514 _hip_d3d_context.VSSetConstantBuffers(desc.BindPoint, 1, &data.buffer); 515 break; 516 case ShaderTypes.GEOMETRY: 517 case ShaderTypes.NONE: 518 break; 519 } 520 } 521 } 522 523 void bindArrayOfTextures(ref ShaderProgram prog, IHipTexture[] textures, string varName) 524 { 525 foreach(i, texture; textures) 526 texture.bind(cast(int)i); 527 } 528 529 void createVariablesBlock(ref ShaderVariablesLayout layout) 530 { 531 import core.stdc.stdlib:malloc; 532 D3D11_BUFFER_DESC desc; 533 desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 534 desc.StructureByteStride=0; 535 desc.MiscFlags = 0; 536 desc.Usage = D3D11_USAGE_DYNAMIC; 537 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 538 desc.ByteWidth = cast(uint)layout.getLayoutSize(); 539 D3D11_SUBRESOURCE_DATA data; 540 data.pSysMem = layout.getBlockData(); 541 542 Hip_D3D11_ShaderVarAdditionalData* d = cast(Hip_D3D11_ShaderVarAdditionalData*) 543 malloc(Hip_D3D11_ShaderVarAdditionalData.sizeof); 544 HRESULT res = _hip_d3d_device.CreateBuffer(&desc, &data, &d.buffer); 545 layout.setAdditionalData(cast(void*)d, true); 546 547 if(FAILED(res)) 548 ErrorHandler.showErrorMessage("D3D11 Error while creating variables block", 549 "Error while creating variable buffer for Shader with type "~to!string(layout.shaderType)); 550 } 551 552 protected __gshared HipBlendFunction currSrc, currDst; 553 protected __gshared HipBlendEquation currEq; 554 555 556 void setBlending(ShaderProgram prog, HipBlendFunction src, HipBlendFunction dest, HipBlendEquation eq) 557 { 558 Hip_D3D11_ShaderProgram p = cast(Hip_D3D11_ShaderProgram)prog; 559 p.blendSrc = src; 560 p.blendDst = dest; 561 p.blendEq = eq; 562 auto b = &Hip_D3D11_Renderer.blend.RenderTarget[0]; 563 564 if(eq == HipBlendEquation.DISABLED) 565 { 566 b.BlendEnable = cast(int)false; 567 } 568 else 569 { 570 b.BlendEnable = cast(int)true; 571 b.SrcBlend = getD3DBlendFunc(src); 572 b.DestBlend = getD3DBlendFunc(dest); 573 b.BlendOp = getD3DBlendEquation(eq); 574 b.BlendOpAlpha = getD3DBlendEquation(eq); 575 576 b.SrcBlendAlpha = getD3DBlendFunc(HipBlendFunction.ZERO); 577 b.DestBlendAlpha = getD3DBlendFunc(HipBlendFunction.ZERO); 578 b.BlendOp = getD3DBlendEquation(HipBlendEquation.ADD); 579 b.BlendOpAlpha = getD3DBlendEquation(HipBlendEquation.ADD); 580 b.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 581 } 582 _hip_d3d_device.CreateBlendState(&Hip_D3D11_Renderer.blend, &p.blendState); 583 } 584 585 586 void deleteShader(FragmentShader* _fs){} 587 void deleteShader(VertexShader* _vs){} 588 void dispose(ref ShaderProgram prog) 589 { 590 Hip_D3D11_ShaderProgram p = cast(Hip_D3D11_ShaderProgram)prog; 591 auto fs = p.fs; 592 if(fs.shader !is null) 593 fs.shader.Release(); 594 fs.shader = null; 595 if(fs.fs !is null) 596 fs.fs.Release(); 597 fs.fs = null; 598 auto vs = p.vs; 599 if(vs.shader !is null) 600 vs.shader.Release(); 601 vs.shader = null; 602 if(vs.vs !is null) 603 vs.vs.Release(); 604 vs.vs = null; 605 } 606 607 bool setShaderVar(ShaderVar* sv, ShaderProgram prog, void* value) 608 { 609 return false; 610 } 611 612 override void onRenderFrameEnd(ShaderProgram){} 613 614 615 }